package com.zhouheng.common.filestore.service.impl;

import com.zhouheng.common.base.exception.RpcFailException;
import com.zhouheng.common.filestore.config.FileStoreProperties;
import com.zhouheng.common.filestore.exception.FileStoreException;
import com.zhouheng.common.filestore.service.FileStoreService;
import io.minio.GetObjectArgs;
import io.minio.GetPresignedObjectUrlArgs;
import io.minio.MinioClient;
import io.minio.ObjectStat;
import io.minio.PutObjectArgs;
import io.minio.StatObjectArgs;
import io.minio.errors.ErrorResponseException;
import io.minio.http.Method;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.InputStream;
import java.util.concurrent.TimeUnit;

@Component
@Slf4j
public class MinioStoreService implements FileStoreService {

    @Autowired
    private MinioClient minioClient;

    @Autowired
    private FileStoreProperties fileStoreProperties;

    private static final long PART_MIN_SIZE = 5 * 1024 * 1024;

    private static final int URL_EXPIRE_MIN = 10;

    @Override
    public void upload(String object, InputStream source, long size) {
        try {
            minioClient.putObject(PutObjectArgs.builder()
                    .bucket(fileStoreProperties.getBucket())
                    .object(object)
                    .stream(source, size, PART_MIN_SIZE).build());
        } catch (Exception e) {
            log.error("上传到Minio失败", e);
            throw new RpcFailException("文件上传Minio异常：" + e.getMessage());
        }
    }

    @Override
    public InputStream download(String object) {
        if (!isObjectExists(object)) {
            throw new FileStoreException(FileStoreException.FILE_NOT_EXISTS);
        }
        return downloadAsInputStream(object);
    }

    private InputStream downloadAsInputStream(String object) {
        try {
            return minioClient.getObject(GetObjectArgs.builder()
                    .bucket(fileStoreProperties.getBucket())
                    .object(object).build());
        } catch (Exception e) {
            log.error("下载Minio失败", e);
            throw new RpcFailException("文件下载Minio异常：" + e.getMessage());
        }
    }

    @Override
    public String getFileUrl(String object) {
        if (!isObjectExists(object)) {
            throw new FileStoreException(FileStoreException.FILE_NOT_EXISTS);
        }

        return getExpirySignedUrl(object, URL_EXPIRE_MIN, Method.GET);
    }


    private String getExpirySignedUrl(String object, int expireInMin, Method method) {
        try {
            return minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
                    .object(object)
                    .bucket(fileStoreProperties.getBucket())
                    .method(method)
                    .expiry(expireInMin, TimeUnit.MINUTES).build());
        } catch (Exception e) {
            log.error("Minio获取对象子连下载失败", e);
            throw new RpcFailException("Minio获取对象子连下载异常：" + e.getMessage());
        }
    }

    private boolean isObjectExists(String object) {
        try {
            ObjectStat response = minioClient.statObject(StatObjectArgs.builder()
                    .bucket(fileStoreProperties.getBucket())
                    .object(object)
                    .build());
            return response.length() > 0;
        } catch (ErrorResponseException e) {
            return false;
        } catch (Exception e) {
            throw new RpcFailException("获取文件状态Minio异常：" + e.getMessage());
        }
    }
}
